package com.ghck.server.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.SetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ghck.server.controller.events.RedisSyncEvent;
import com.ghck.server.dao.DiseaseBodypartRelMapper;
import com.ghck.server.dao.DiseaseMapper;
import com.ghck.server.dao.DiseaseSearchHistoryMapper;
import com.ghck.server.exception.GhckException;
import com.ghck.server.exception.ErrorConstant;
import com.ghck.server.model.BodypartDict;
import com.ghck.server.model.Disease;
import com.ghck.server.model.DiseaseBodypartRel;
import com.ghck.server.model.DiseaseCategoryDict;
import com.ghck.server.model.DiseaseReq;
import com.ghck.server.model.DiseaseSearchHistory;
import com.ghck.server.model.Symptom;
import com.ghck.server.model.query.DiseaseQuery;
import com.ghck.server.model.response.DiseaseRes;
import com.ghck.server.model.response.IdNameRes;
import com.ghck.server.service.BodypartDictService;
import com.ghck.server.service.DiseaseService;
import com.ghck.server.utils.IntegerUtil;
import com.ghck.server.utils.RedisKeyUtil;
import com.ghck.server.utils.SpringContextUtil;

/**
 * 疾病库表  <br>
 * t_disease <br>
 * v1.0 2016-05-01
 */
@Service
@Transactional
public class DiseaseServiceImpl implements DiseaseService {

	private static final Logger logger = LoggerFactory.getLogger(DiseaseServiceImpl.class);

	@Autowired
	private DiseaseMapper diseaseMapper;

	@Autowired
	DiseaseBodypartRelMapper diseaseBodypartRelMapper;

	@Autowired
	RedisTemplate<String,Object> template;
	
	@Autowired
	BodypartDictService bodypartDictService;
	
	@Autowired
	private DiseaseSearchHistoryMapper diseaseSearchHistoryMapper;

	/**
	 *根据ID删除 疾病库表
	 */
	@Override
	public Integer deleteDiseaseById(Integer id){
		return diseaseMapper.deleteById(id);
	}

	/**
	 *新增 疾病库表
	 */
	@Override
	@Transactional
	public Integer batchInsertDisease(List<? extends Disease> diseases){
		Integer count = diseaseMapper.batchInsert(diseases);
		return count;
	}
	/**
	 *新增 疾病库表
	 */
	@Override
	@Transactional
	public Integer insertDisease(DiseaseReq domain){
//		String name = domain.getName();

//		Disease diseaseDb = diseaseMapper.findByName(name);
//		if(diseaseDb!=null){
//			GhckException exception = new GhckException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"【"+name+"】疾病已存在！请确认");
//			logger.info("添加疾病失败",exception);
//			throw exception;
//		}
		diseaseMapper.insert(domain);
		Integer diseaseId = domain.getId();
		if(IntegerUtil.isPositiveInteger(diseaseId)){
			List<Integer> bodypartIdList = domain.getBodypartIds();
			List<DiseaseBodypartRel> rels = new ArrayList<>();
			for (Integer integer : bodypartIdList) {
				DiseaseBodypartRel rel = new DiseaseBodypartRel();
				rel.setBodyPartId(integer);
				rel.setDiseaseId(diseaseId);
				rel.setInUsed(1);
				rels.add(rel);
			}
			if (CollectionUtils.isNotEmpty(rels)) {
				diseaseBodypartRelMapper.batchInsert(rels);
			}

			//同步关系
			RedisSyncEvent event = new RedisSyncEvent(diseaseId, RedisSyncEvent.DISEASE);
			SpringContextUtil.getApplicationContext().publishEvent(event);
		}
		return diseaseId;
	}

	/**
	 *更新 疾病库表
	 */
	@Override
	@Transactional
	public Integer updateDisease(DiseaseReq domain){
		Integer diseaseId = domain.getId();
		Disease diseaseDb = diseaseMapper.findById(diseaseId);
		if(diseaseDb==null){
			GhckException exception = new GhckException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"diseaseId="+diseaseId+"的疾病不存在");
			logger.info("修改疾病失败",exception);
			throw exception;
		}

		List<DiseaseBodypartRel> dbRelList = diseaseBodypartRelMapper.findByDiseaseId(diseaseId);

		Set<DiseaseBodypartRel> dbRelSet = new HashSet<>(dbRelList);
		Set<DiseaseBodypartRel> paramRelSet = new HashSet<>();

		List<Integer> newBodypartIdList = domain.getBodypartIds();
		if (CollectionUtils.isNotEmpty(newBodypartIdList)) {
			for (Integer integer : newBodypartIdList) {
				DiseaseBodypartRel rel = new DiseaseBodypartRel();
				rel.setBodyPartId(integer);
				rel.setDiseaseId(diseaseId);
				rel.setInUsed(1);
				paramRelSet.add(rel);
			}
		}

		//需要删除的
		Set<DiseaseBodypartRel> deletes = SetUtils.difference(dbRelSet,paramRelSet); //差集
		//需要新增的
		Set<DiseaseBodypartRel> news = SetUtils.difference(paramRelSet,dbRelSet);

		if (CollectionUtils.isNotEmpty(deletes)) {
			for (DiseaseBodypartRel diseaseBodypartRel : deletes) {
				if(diseaseBodypartRel.getInUsed()==1){
					diseaseBodypartRel.setInUsed(0);
					diseaseBodypartRelMapper.update(diseaseBodypartRel);
				}
			}
		}

		if (CollectionUtils.isNotEmpty(news)) {
			diseaseBodypartRelMapper.batchInsert(new ArrayList<>(news));
		}

		diseaseMapper.update(domain);

		//同步关系
		RedisSyncEvent event = new RedisSyncEvent(diseaseId, RedisSyncEvent.DISEASE);
		SpringContextUtil.getApplicationContext().publishEvent(event);

		return diseaseId;
	}

	@Override
	public Integer disableDisease(Integer diseaseId) {
		Disease diseaseDb = diseaseMapper.findById(diseaseId);
		if(diseaseDb==null){
			GhckException exception = new GhckException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"diseaseId="+diseaseId+"的疾病不存在");
			logger.info("禁用疾病失败",exception);
			throw exception;
		}
		diseaseDb.setInUsed(0);

		diseaseMapper.update(diseaseDb);

		//同步关系
		RedisSyncEvent event = new RedisSyncEvent(diseaseId, RedisSyncEvent.DISEASE);
		SpringContextUtil.getApplicationContext().publishEvent(event);

		return diseaseId;
	}

	@Override
	public Integer enableDisease(Integer diseaseId) {
		Disease diseaseDb = diseaseMapper.findById(diseaseId);
		if(diseaseDb==null){
			GhckException exception = new GhckException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"diseaseId="+diseaseId+"的疾病不存在");
			logger.info("启用疾病失败",exception);
			throw exception;
		}

		diseaseDb.setInUsed(1);

		diseaseMapper.update(diseaseDb);

		//同步关系
		RedisSyncEvent event = new RedisSyncEvent(diseaseId, RedisSyncEvent.DISEASE);
		SpringContextUtil.getApplicationContext().publishEvent(event);

		return diseaseId;
	}

	/**
	 *根据ID查询 疾病库表
	 */
	public Disease findDiseaseById(Integer id){
		Disease result = diseaseMapper.findById(id);
		if(result!=null){
			result.dealWith();
		}
		return result;
	}

	public Disease findDiseaseByIdWithCache(Integer id){
		String key = RedisKeyUtil.diseaseHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		String hashKey = RedisKeyUtil.domainIdKey(id);

		HashOperations<String,String,Disease> aa = template.opsForHash();
		
		Disease object = aa.get(key, hashKey);

		String diseaseIdMapBodyPartIdNameKey = RedisKeyUtil.diseaseIdMapBodyPartIdNameList();
		
		HashOperations<String,String,List<IdNameRes>> bb = template.opsForHash();
		
		List<IdNameRes> idNames =  bb.get(diseaseIdMapBodyPartIdNameKey, hashKey);
		
		object.setBodyparts(idNames);

		return object;
	}

	/**
	 *通过query 查询 疾病库表
	 */
	public List<DiseaseRes> findDiseaseByQuery(DiseaseQuery query){
		
		//记录搜索历史
		DiseaseSearchHistory diseaseSearchHistory = new DiseaseSearchHistory();
		diseaseSearchHistory.setKeyword(query.getKeyword());
		diseaseSearchHistory.setUserId(query.getUserId());
		diseaseSearchHistory.setStationId(query.getStationId());
		diseaseSearchHistoryMapper.insert(diseaseSearchHistory);
		
		query.dealWith();
		List<DiseaseRes> result = diseaseMapper.findDiseaseListForKeyword(query);
		if(CollectionUtils.isNotEmpty(result)) {
			for (Disease disease : result) {
				disease.dealWith();
			}
		}
		return result;
	}
	
	@Override
	public List<DiseaseRes> managerList(DiseaseQuery query) {
		query.dealWith();
		List<DiseaseRes> result = diseaseMapper.findByQueryRes(query);
		if(CollectionUtils.isNotEmpty(result)) {
			for (DiseaseRes disease : result) {
				disease.setBodypartIds(diseaseMapper.getDiseaseBybodypartIds(disease.getId()));
				disease.dealWith();
			}
		}
		return result;
	}

	/**
	 *通过query count总条数
	 */
	public Integer countDiseaseByQuery(DiseaseQuery query){
		query.dealWith();
		Integer result = diseaseMapper.countByQuery(query);
		return result;
	}

	/**
	 * 通过ids查询
	 */
	public List<Disease> findDiseaseByIds(List<Integer> ids){
		List<Disease> result = diseaseMapper.findByIds(ids);
		if(CollectionUtils.isNotEmpty(result)) {
			for (Disease disease : result) {
				disease.dealWith();
			}
		}
		return result;
	}

	public List<DiseaseCategoryDict> getDiseaseByCategoryDicts(){

		return null;
	}

	@Override
	public List<DiseaseCategoryDict> getDiseaseByCategoryId(Integer categoryId) {

		return diseaseMapper.getDiseaseByCategoryId(categoryId);
	}

	@Override
	public List<IdNameRes> findDiseaseByBodypartId(Integer bodypartId) {

		List<IdNameRes> list = diseaseMapper.findDiseaseByBodypartId(bodypartId);

		return list;
	}

	@Override
	public void syncInRedis(boolean force) {
		String key = RedisKeyUtil.diseaseHashKey();
		if(force || (!template.hasKey(key) )){
			template.delete(key);
			List<Disease> res = diseaseMapper.findAll();
			if (CollectionUtils.isNotEmpty(res)) {
				Map<String, Disease> map = new HashMap<String, Disease>();
				for (Disease disease : res) {
					String hashKey = RedisKeyUtil.domainIdKey(disease.getId());
					map.put(hashKey, disease);
				}
				if(!map.isEmpty())
				{
					template.opsForHash().putAll(key, map);
//					template.expire(key, 30, TimeUnit.DAYS);
				}

				//为了缓存总获取bodypart，确保它先同步，他的同步不依赖其他同步。
				bodypartDictService.syncInRedis(false);
				String bodypartHashKey = RedisKeyUtil.bodypartHashKey();
				HashOperations<String, String, BodypartDict> bodypartHO = null;
				
				//同步中间表 in_used=1
				List<DiseaseBodypartRel> diseaseBodypartRelList = diseaseBodypartRelMapper.findAll();
				String bodyIdMapDiseaseIdNameKey = RedisKeyUtil.bodyIdMapDiseaseIdNameList();
				String diseaseIdMapBodyPartIdNameKey = RedisKeyUtil.diseaseIdMapBodyPartIdNameList();
				template.delete(bodyIdMapDiseaseIdNameKey);
				template.delete(diseaseIdMapBodyPartIdNameKey);
				if (CollectionUtils.isNotEmpty(diseaseBodypartRelList)) {
					Map<String, List<IdNameRes>> bodyIdMapRel = new HashMap<String, List<IdNameRes>>();
					Map<String, List<IdNameRes>> diseaseIdMapRel = new HashMap<String, List<IdNameRes>>();
					for (DiseaseBodypartRel diseaseBodypartRel : diseaseBodypartRelList) {
						Integer diseaseId = diseaseBodypartRel.getDiseaseId();
						String diseaseHashKey = RedisKeyUtil.domainIdKey(diseaseId);
						Disease disease = map.get(RedisKeyUtil.domainIdKey(diseaseId));
						if(disease!=null){
							Integer bodyId = diseaseBodypartRel.getBodyPartId();
							String hashKey = RedisKeyUtil.domainIdKey(bodyId);
							if(!bodyIdMapRel.containsKey(hashKey)){
								bodyIdMapRel.put(hashKey, new ArrayList<IdNameRes>());
							}
							bodyIdMapRel.get(hashKey).add(disease.toIdNameRes());
						}
						
						Integer bodypartId = diseaseBodypartRel.getBodyPartId();
						String bodyHashKey = RedisKeyUtil.domainIdKey(bodypartId);
						bodypartHO = template.opsForHash();
						BodypartDict bodydict = bodypartHO.get(bodypartHashKey, bodyHashKey);
						if(bodydict!=null){
							if(!diseaseIdMapRel.containsKey(diseaseHashKey)){
								diseaseIdMapRel.put(diseaseHashKey, new ArrayList<IdNameRes>());
							}
							diseaseIdMapRel.get(diseaseHashKey).add(bodydict.toIdNameRes());
						}
						
					}
					if(!bodyIdMapRel.isEmpty()){
						template.opsForHash().putAll(bodyIdMapDiseaseIdNameKey, bodyIdMapRel);
//						template.expire(bodyIdMapDiseaseIdNameKey, 30, TimeUnit.DAYS);
					}
					if(!diseaseIdMapRel.isEmpty()){
						template.opsForHash().putAll(diseaseIdMapBodyPartIdNameKey, diseaseIdMapRel);
//						template.expire(diseaseIdMapBodyPartIdNameKey, 30, TimeUnit.DAYS);
					}
				}
			}
		}

	}

	@Override
	public void syncSingletonRedis(Integer diseaseId) {

		String key = RedisKeyUtil.diseaseHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}else{
			Disease disease = diseaseMapper.findById(diseaseId);
			String hashKey = RedisKeyUtil.domainIdKey(diseaseId);
			
			String diseaseIdMapBodyPartIdNameKey = RedisKeyUtil.diseaseIdMapBodyPartIdNameList();
			
			if(disease.getInUsed()==1){
				template.opsForHash().put(key, hashKey, disease);
			}else{
				template.opsForHash().delete(key, hashKey);
				template.opsForHash().delete(diseaseIdMapBodyPartIdNameKey, hashKey);
			}

			//为了缓存总获取bodypart，确保它先同步，他的同步不依赖其他同步。
			bodypartDictService.syncInRedis(false);
			String bodypartHashKey = RedisKeyUtil.bodypartHashKey();
			HashOperations<String, String, BodypartDict> bodypartHO = null;
			
			List<DiseaseBodypartRel> relList = diseaseBodypartRelMapper.findByDiseaseId(diseaseId);
			if (CollectionUtils.isNotEmpty(relList)) {
				List<IdNameRes> bodyIdNameList = new ArrayList<IdNameRes>();
				
				String bodyIdMapDiseaseIdNameKey = RedisKeyUtil.bodyIdMapDiseaseIdNameList();
				for (DiseaseBodypartRel diseaseBodypartRel : relList) {
					hashKey = RedisKeyUtil.domainIdKey(diseaseBodypartRel.getBodyPartId());
					
					HashOperations<String, String, List<IdNameRes>> hOperations = template.opsForHash();
					List<IdNameRes> list = hOperations.get(bodyIdMapDiseaseIdNameKey, hashKey);
					if (CollectionUtils.isNotEmpty(list)) {
						boolean find =false;
						Object findObject = null;
						for (IdNameRes idNameRes : list) {
							if(diseaseId.intValue() == idNameRes.getId()){
								find = true;
								findObject = idNameRes;
								break;
							}
						}
						if(!find){
							if(disease.getInUsed()==1 && diseaseBodypartRel.getInUsed()==1){
								list.add(disease.toIdNameRes());
								template.opsForHash().put(bodyIdMapDiseaseIdNameKey, hashKey,list);
							}
						}else{
							if(disease.getInUsed()==1 && diseaseBodypartRel.getInUsed()==0){ //疾病为删除，但是移动到另外的地方去了，->删除原来的 
								list.remove(findObject);
								template.opsForHash().put(bodyIdMapDiseaseIdNameKey, hashKey,list);
							}
							if(disease.getInUsed()==0){ //疾病删除了->在列表中也应该去掉
								list.remove(findObject);
								template.opsForHash().put(bodyIdMapDiseaseIdNameKey, hashKey,list);
							}
						}
					}else if(disease.getInUsed()==1 && diseaseBodypartRel.getInUsed()==1){
						list = new ArrayList<IdNameRes>();
						list.add(disease.toIdNameRes());
						template.opsForHash().put(bodyIdMapDiseaseIdNameKey, hashKey,list);
					}
					
					//同步 diseaseId - BodyIdNameList
					if(disease.getInUsed()==1 && diseaseBodypartRel.getInUsed()==1){
						Integer bodypartId = diseaseBodypartRel.getBodyPartId();
						String bodyHashKey = RedisKeyUtil.domainIdKey(bodypartId);
						bodypartHO = template.opsForHash();
						BodypartDict bodydict = bodypartHO.get(bodypartHashKey, bodyHashKey);
						if(bodydict!=null){
							bodyIdNameList.add(bodydict.toIdNameRes());
						}
					}
				}
				
				// diseaseId - BodyIdNameList 入Redis
				if(disease.getInUsed()==1 && CollectionUtils.isNotEmpty(bodyIdNameList)){
					template.opsForHash().put(diseaseIdMapBodyPartIdNameKey, hashKey, bodyIdNameList);
				}
				
			}
		}
	}

	@Override
	public List<Symptom> findSymptonListByBodypartId(Integer bodypartId) {
		List<Symptom> list = diseaseMapper.findSymptonListByBodypartId(bodypartId);
		return list;
	}

	@Override
	public List<DiseaseRes> findDiseaseListForSymptomId(DiseaseQuery query) {
		List<DiseaseRes>  list = diseaseMapper.findDiseaseListForSymptomId(query);
		return list;
	}
	
}	